/* ----------------------------------------------------------------------
*
* Copyright (C) 2025 XiaoFei. All rights reserved.
*
* @file:		XiaoZhi_BMP280.c
* @author:		XiaoFei
* @Date:     	20-January-2025
* @Revision: 	V1
* @Project: 	XiaoFei BSP Library
*
* -------------------------------------------------------------------- */

#include "stm32f10x.h"
#include "XiaoZhi_BMP280.h"

#ifdef BMP280_UseI2C
/* 
* @function: 	BMP280_SendByte
* @parameter:	[in] Reg				    The reg will be send to BMP280 device by I2C.
*/
static void BMP280_SendByte(unsigned char Reg)
{
	for(unsigned char i=0;i<8;i++)
	{
		BMP280_SDA(!!(Reg&(0x80>>i)));
		BMP280_SCL(1);
		BMP280_SCL(0);
	}
	BMP280_SDA(1);	
	BMP280_SCL(1);	
	BMP280_SDARead;	
	BMP280_SCL(0);	
}
#endif

#ifdef BMP280_UseI2C
/* 
* @function: 	BMP280_ReadByte
* @return:		The data will be read from BMP280 device by I2C.
*/
static unsigned char BMP280_ReadByte(void)
{
	unsigned char Byte=0x00;
	BMP280_SDA(1);
	for(unsigned char i=0;i<8;i++)
	{
		BMP280_SCL(1);	
		if(BMP280_SDARead)
			Byte|=(0x80>>i);
		BMP280_SCL(0);	
	}
	BMP280_SDA(1);				
	BMP280_SCL(1);						
	BMP280_SCL(0);		
	return Byte;
}
#endif

#ifdef BMP280_UseSPI
/* 
* @function: 	BMP280_SwapByte
* @parameter:	[in] ByteSend				The reg will be to from BMP280 device by SPI.
* @return:		The data will be read from BMP280 device by SPI.
*/
static unsigned char BMP280_SwapByte(unsigned char ByteSend)
{
	unsigned char ByteReceive=0x00;
	for (unsigned char i=0;i<8;i++)
	{
		BMP280_MOSI(!!(ByteSend&(0x80>>i)));	
		BMP280_SCK(1);							
		if(BMP280_MISORead)
			ByteReceive|=(0x80>>i);
		BMP280_SCK(0);								
	}
	return ByteReceive;
}
#endif
		
/* 
* @function: 	BMP280_SendByte
* @parameter:	[in] RegAddress				The reg address in BMP280 device.
* @parameter:	[in] data				    The data will be send to BMP280 device.
*/
static void BMP280_SendReg(unsigned int RegAddress, unsigned char data)
{
	#ifdef BMP280_UseI2C
		BMP280_SDA(1);				
		BMP280_SCL(1);				
		BMP280_SDA(0);				
		BMP280_SCL(0);						
		BMP280_SendByte((BMP280_Address<<1)|0x00);				
		BMP280_SendByte(RegAddress);	
		BMP280_SendByte(data);						
		BMP280_SDA(0);				
		BMP280_SCL(1);				
		BMP280_SDA(1);		
	#endif	
	#ifdef BMP280_UseSPI
		BMP280_CS(0);
		BMP280_SwapByte(RegAddress&0x7F);
		BMP280_SwapByte(data);
		BMP280_CS(1);
	#endif
}

/* 
* @function: 	BMP280_ReadReg
* @parameter:	[in] RegAddress				The reg address in BMP280 device.
* @return:		The data will be read from BMP280 device.
*/
static unsigned char BMP280_ReadReg(unsigned char RegAddress)
{
	#ifdef BMP280_UseI2C
		unsigned char Data;
		BMP280_SDA(1);				
		BMP280_SCL(1);				
		BMP280_SDA(0);				
		BMP280_SCL(0);	
		BMP280_SendByte((BMP280_Address<<1)|0x00);				
		BMP280_SendByte(RegAddress);			
		BMP280_SDA(1);				
		BMP280_SCL(1);				
		BMP280_SDA(0);				
		BMP280_SCL(0);		
		BMP280_SendByte((BMP280_Address<<1)|0x01);	
		Data = BMP280_ReadByte();			
		BMP280_SDA(0);				
		BMP280_SCL(1);				
		BMP280_SDA(1);						
		return Data;
	#endif	
	#ifdef BMP280_UseSPI
		BMP280_CS(0);
		BMP280_SwapByte(RegAddress);
		unsigned char Data=BMP280_SwapByte(0xFF);
		BMP280_CS(1);
		return Data;
	#endif
}

/* 
* @function: 	BMP280_GetID
* @return:		Device ID number of BMP280 device.
*/
unsigned char BMP280_GetID(void)
{
	unsigned char ID;
	ID=BMP280_ReadReg(BMP280_ID);
	return ID;
}

/* 
* @function: 	BMP280_GetDevice
* @parameter:	[out] BMP280				The important device data from BMP280 device.
*/
void BMP280_GetDevice(BMP280_TypeDef* BMP280)
{
	unsigned char buf[20];
	for(unsigned char i=0;i<6;i++)
		buf[i]=BMP280_ReadReg(BMP280_DIGT+i);
	BMP280->dig_t1=(unsigned short)(BMP280_Ex(buf[1],buf[0]));
	BMP280->dig_t2=(signed short)(BMP280_Ex(buf[3],buf[2]));
	BMP280->dig_t3=(signed short)(BMP280_Ex(buf[5],buf[4]));
	for(unsigned char i=0;i<18;i++)
		buf[i]=BMP280_ReadReg(BMP280_DIGP+i);
	BMP280->dig_p1=(unsigned short)(BMP280_Ex(buf[1],buf[0]));
	BMP280->dig_p2=(signed short)(BMP280_Ex(buf[3],buf[2]));
	BMP280->dig_p3=(signed short)(BMP280_Ex(buf[5],buf[4]));
	BMP280->dig_p4=(signed short)(BMP280_Ex(buf[7],buf[6]));
	BMP280->dig_p5=(signed short)(BMP280_Ex(buf[9],buf[8]));
	BMP280->dig_p6=(signed short)(BMP280_Ex(buf[11],buf[10]));
	BMP280->dig_p7=(signed short)(BMP280_Ex(buf[13],buf[12]));
	BMP280->dig_p8=(signed short)(BMP280_Ex(buf[15],buf[14]));
	BMP280->dig_p9=(signed short)(BMP280_Ex(buf[17],buf[16]));
}

/* 
* @function: 	BMP280_SetuOverSamp
* @parameter:	[out] osrs_p				The over sampling data to BMP280 device.
* @parameter:	[out] osrs_t				The over sampling data to BMP280 device.
*/
void BMP280_SetuOverSamp(unsigned char osrs_p, unsigned char osrs_t)
{
	unsigned char temp=BMP280_ReadReg(BMP280_CTRL_MEAS);
	temp&=0xE3;
	osrs_p=osrs_p<<2;
	osrs_p&=0x1C;
	temp|=osrs_p;
	temp&=0x1F;
	osrs_t=osrs_t<<5;
	osrs_t&=0xE0;
	temp|=osrs_t;
	BMP280_SendReg(BMP280_CTRL_MEAS,temp);
}

/* 
* @function: 	BMP280_SetConfige
* @parameter:	[out] Standbyt				The standard sampling interval to BMP280.
* @parameter:	[out] filter				The standard filter order to BMP280.
*/
void BMP280_SetConfige(BMP280_StandBytDef Standbyt, BMP280_FilterDef filter)
{
	unsigned char temp=Standbyt<<5;
	unsigned char fil=filter;
	fil&=0x07;
	fil=fil<<2;
	temp|=fil;
	BMP280_SendReg(BMP280_CONFIG,temp);
}

/* 
* @function: 	BMP280_SetMode
* @parameter:	[out] mode				    The working mode to BMP280.
*/
void BMP280_SetMode(BMP280_MoodDef mode)
{
	unsigned char temp=BMP280_ReadReg(BMP280_CTRL_MEAS);
	switch(mode)
	{
		case BMP280_Sleep:
			temp&=0xFC;
		    break;
		case BMP280_Single:
			temp&=0xFC;
		    temp|=0x01;
		    break;
		case BMP280_Continuous:
			temp&=0xFC;
		    temp|=0x03;	
		    break;
		default:
			return;
	}
	BMP280_SendReg(BMP280_CTRL_MEAS,temp);
}

/* 
* @function: 	BMP280_Check
* @parameter:	[out] BMP280				The BMP280 device will be initialized.
* @return:		Return 0x00 when the BMP280 device is initialized.
*/
unsigned char BMP280_Check(BMP280_TypeDef* BMP280)
{
	if(BMP280_GetID()==BMP280_CHIP_ID)
	{
		BMP280_GetDevice(BMP280);
		BMP280_SetuOverSamp(5,2);
		BMP280_SetConfige(BMP280_Sta1ms,BMP280_Filter16);
		BMP280_SetMode(BMP280_Continuous);
		return 0x00;
	}
	else
		return 0x01;
}

/* 
* @function: 	BMP280_Init
* @parameter:	[out] BMP280				The BMP280 device will be initialized.
*/
void BMP280_Init(BMP280_TypeDef* BMP280)
{
	#ifdef BMP280_UseI2C
		RCC_APB2PeriphClockCmd(BMP280_RCC_SDA,ENABLE);
		GPIO_InitTypeDef GPIO_InitStructure;
		GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;
		GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Pin=BMP280_PIN_SDA;
		GPIO_Init(BMP280_GPIO_SDA,&GPIO_InitStructure);
		RCC_APB2PeriphClockCmd(BMP280_RCC_SCL,ENABLE);
		GPIO_InitStructure.GPIO_Pin=BMP280_PIN_SCL;
		GPIO_Init(BMP280_GPIO_SCL,&GPIO_InitStructure);
		BMP280_SCL(1);
	    BMP280_SDA(1);
	#endif
	#ifdef BMP280_UseSPI
		RCC_APB2PeriphClockCmd(BMP280_RCC_CS,ENABLE);
		GPIO_InitTypeDef GPIO_InitStructure;
		GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
		GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Pin=BMP280_PIN_CS;
		GPIO_Init(BMP280_GPIO_CS,&GPIO_InitStructure);
		RCC_APB2PeriphClockCmd(BMP280_RCC_SCK,ENABLE);
		GPIO_InitStructure.GPIO_Pin=BMP280_PIN_SCK;
		GPIO_Init(BMP280_GPIO_SCK,&GPIO_InitStructure);
		RCC_APB2PeriphClockCmd(BMP280_RCC_MOSI,ENABLE);
		GPIO_InitStructure.GPIO_Pin=BMP280_PIN_MOSI;
		GPIO_Init(BMP280_GPIO_MOSI,&GPIO_InitStructure);
		RCC_APB2PeriphClockCmd(BMP280_RCC_MISO,ENABLE);
		GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
		GPIO_InitStructure.GPIO_Pin=BMP280_PIN_MISO;
		GPIO_Init(BMP280_GPIO_MISO,&GPIO_InitStructure);
		BMP280_CS(1);
		BMP280_SCK(0);
	#endif
	while(BMP280_Check(BMP280));
}

/* 
* @function: 	BMP280_GetTemp
* @parameter:	[in] BMP280				    The BMP280 device will be initialized.
* @parameter:	[out] t_fine				Auxiliary data for function BMP280_GetPres.
* @return:		Temperature measurement results from BMP280.
*/
double BMP280_GetTemp(BMP280_TypeDef *BMP280, int* t_fine)
{
	unsigned char buf[3];
	for(unsigned char i=0;i<3;i++)
		buf[i]=BMP280_ReadReg(BMP280_TEMP+i);
	unsigned int data_msb=(int)buf[0]<<12;
	unsigned int data_lsb=(int)buf[1]<<4;
	unsigned int data_xlsb=(int)buf[2]>>4;
	int uncomp_temperature=(int)(data_msb|data_lsb|data_xlsb);
	double var1=(((double)uncomp_temperature)/16384.0-((double)BMP280->dig_t1)/1024.0)*((double) BMP280->dig_t2);
	double var2=((((double)uncomp_temperature)/131072.0-((double)BMP280->dig_t1)/8192.0)*
				(((double)uncomp_temperature)/131072.0-((double)BMP280->dig_t1)/8192.0))*((double)BMP280->dig_t3);
	*t_fine=(int)(var1+var2);
	return (var1+var2)/5120.0;
}

/* 
* @function: 	BMP280_GetPres
* @parameter:	[in] BMP280				    The BMP280 device will be initialized.
* @parameter:	[in] t_fine				    Auxiliary data from function BMP280_GetTemp.
* @return:		Air pressure measurement results from BMP280.
*/
double BMP280_GetPres(BMP280_TypeDef *BMP280, int* t_fine)
{
    unsigned char buf[3];
	for(unsigned char i=0;i<3;i++)
		buf[i]=BMP280_ReadReg(BMP280_PRES+i);
	unsigned int data_msb=(unsigned int)buf[0]<<12;
    unsigned int data_lsb=(unsigned int)buf[1]<<4;
    unsigned int data_xlsb=(unsigned int)buf[2]>>4;
	int uncomp_pressure=(data_msb|data_lsb|data_xlsb);
	double var1=((double)*t_fine/2.0)-64000.0;
    double var2=var1*var1*((double)BMP280->dig_p6)/32768.0;
    var2=var2+var1*((double)BMP280->dig_p5)*2.0;
    var2=(var2/4.0)+(((double)BMP280->dig_p4)*65536.0);
    var1=(((double)BMP280->dig_p3)*var1*var1/524288.0+((double)BMP280->dig_p2)*var1)/524288.0;
    var1=(1.0 + var1/32768.0)*((double)BMP280->dig_p1);
    double pressure=1048576.0-(double)uncomp_pressure;
    pressure=(pressure-(var2/4096.0))*6250.0/var1;
    var1=((double)BMP280->dig_p9)*pressure*pressure/2147483648.0;
    var2=pressure*((double)BMP280->dig_p8)/32768.0;
    return (pressure+(var1+var2+((double)BMP280->dig_p7))/16.0)/1000.0;
}	


